{ ----------------------------------------------------------------------------
  Amstrad Notepad emulator
  Copyright (c) Michael Nixon (Zipplet) 2011.
  http://www.zipplet.co.uk/
  Licensed under the MIT license, please see mit_license.txt in the
  documentation directory.

  Notepad state
  ---------------------------------------------------------------------------- }
unit notepadstate;

interface

uses classes, globals;

const
  dummymemsize = 256;

  { System IO locations }
  io_display_start = $00;
  io_mmc = $10;
  io_mmc_range = $3;
  io_card_wait = $20;
  io_baud_etc = $30;
  io_parallel_data = $40;
  io_speaker = $50;
  io_speaker_range = $3;
  io_irq_mask = $60;
  io_power_control = $70;
  io_irq_status = $90;
  io_card_status = $A0;
  io_keyboard = $B0;
  io_keyboard_range = $B9;
  io_uart = $C0;
  io_uart_range = $1;
  io_rtc = $D0;
  io_rtc_range = $F;

type
  eSystem = (eSystemNC100, eSystemNC200);
  eMemType = (eMemTypeRAM, eMemTypeROM, eMemTypeCard);

  { --------------------------------------------------------------------------
    tnotepadstate: Holds emulation state
    Any emulation state that is private to a system component and does not need
    to be shared by other components is instead defined locally to that
    component. This object only holds state that is used by multiple components
    or is shared between components.
    -------------------------------------------------------------------------- }
  tnotepadstate = class(tobject)
    private
    protected
    public
      { ----------------------------------------------------------------------
        Machine memory
        ---------------------------------------------------------------------- }

      { System RAM }
      ram: pbytearr;
      ramsize: longint;

      { System ROM (Firmware) }
      rom: pbytearr;
      romsize: longint;

      { Card RAM }
      cardram: pbytearr;
      cardramsize: longint;
      cardpresent: boolean;

      { Dummy memory (256 bytes in size) }
      dummymem: pbytearr;

      { Memory map - these pointers are used to handle memory access. The
        upper 8 bits of the address accessed is used as an index into the
        memory map, and the lower 8 bits of the address are an index into
        the result. }
      memmap: array[$00..$FF] of pbytearr;
      memmaptype: array[$00..$FF] of eMemType;

      { System type }
      systemType: eSystem;

      { ----------------------------------------------------------------------
        LCD state
        ---------------------------------------------------------------------- }

      { Start address of LCD data - the upper 4 bits control A15-A12 }
      lcd_startaddr: byte;

      { ----------------------------------------------------------------------
        Memory state
        ---------------------------------------------------------------------- }

      { Memory management control }
      mem_ctrl: array[0..3] of byte;

      { Card RAM wait state. TRUE = slow card (200nS or slower), FALSE = fast card }
      card_waitstate: boolean;


      { ---------------------------------------------------------------------- }

      constructor Create(cSystemType: eSystem; cRamSize: longint;
        cRomSize: longint);
      destructor Destroy; override;

      { SRAM card functions }
      procedure createCard(cCardRamSize: longint);
      procedure destroyCard;

      { Memory manipulation }
      procedure zeroSystemRAM;
  end;

implementation

{ ----------------------------------------------------------------------------
  Zero out all of the system memory
  ---------------------------------------------------------------------------- }
procedure tnotepadstate.zeroSystemRAM;
begin
  fillchar(self.ram^, self.ramsize, 0);
end;

{ ----------------------------------------------------------------------------
  Create the memory for an SRAM card of size <cCardRamSize> (bytes)
  ---------------------------------------------------------------------------- }
procedure tnotepadstate.createCard(cCardRamSize: longint);
begin
  self.cardramsize := cCardRamSize;
  getmem(self.cardram, self.cardramsize);
end;

{ ----------------------------------------------------------------------------
  Destroy the memory previously allocated for an SRAM card. Does nothing if
  no memory has been allocated.
  ---------------------------------------------------------------------------- }
procedure tnotepadstate.destroyCard;
begin
  if assigned(self.cardram) then begin
    freemem(self.cardram);
    self.cardram := nil;
    self.cardramsize := 0;
    self.cardpresent := false;
  end;
end;

{ ----------------------------------------------------------------------------
  tnotepadstate constructor
  ---------------------------------------------------------------------------- }
constructor tnotepadstate.Create(cSystemType: eSystem; cRamSize: longint; cRomSize: longint);
var
  i: longint;
begin
  inherited Create;
  {}
  { Basic initialisation of the emulation state }
  self.systemType := cSystemType;
  self.romsize := cRomSize;
  self.ramsize := cRamSize;
  self.cardram := nil;
  self.cardramsize := 0;
  self.cardpresent := false;

  { Allocate memory blocks - we could use allocmem to zero fill as well but
    that is a waste of time as most of the time the emulator will be resuming
    a state, so the RAM will be read from a file }
  self.dummymem := allocmem(dummymemsize);
  getmem(self.ram, self.ramsize);
  getmem(Self.rom, self.romsize);

  { Map dummy memory into the entire memory map }
  for i := $00 to $FF do begin
    self.memmap[i] := self.dummymem;
    self.memmaptype[i] := eMemTypeROM;
  end;
end;

{ ----------------------------------------------------------------------------
  tnotepadstate destructor
  ---------------------------------------------------------------------------- }
destructor tnotepadstate.Destroy;
begin
  { Dispose of emulated SRAM card }
  self.DestroyCard;

  { Get rid of memory blocks we allocated earlier }
  if assigned(self.dummymem) then begin
    freemem(self.dummymem);
    self.dummymem := nil;
  end;
  if assigned(self.ram) then begin
    freemem(self.ram);
    self.ram := nil;
  end;
  if assigned(self.rom) then begin
    freemem(self.rom);
    self.rom := nil;
  end;
  {}
  inherited Destroy;
end;

end.
